#include "bsp_uart.h"
#include "bsp_define.h"
uint8_t uart1_txbuf[TX_LEN],uart1_rxbuf[RX_LEN];
uint8_t uart2_txbuf[TX_LEN],uart2_rxbuf[RX_LEN];
uint8_t uart1_rx_cnt = 0,uart1_w_pos = 0,uart1_r_pos = 0,uart2_rx_cnt = 0,uart2_w_pos = 0,uart2_r_pos = 0;
UART_TypeDef* SY_UART_UNIT_Map[2] = {
    SYM_UART1,
    SYM_UART2,
};
const uint16_t Parity_Mode_Map[4] = {
    UART_PARITYMODE_NONE,
    UART_PARITYMODE_EVEN,
    UART_PARITYMODE_ODD,
    UART_PARITYMODE_CUSTOM,
};
const uint16_t Stop_Bits_Map[3] = {
    UART_STOPBITS_1,
    UART_STOPBITS_1P5,
    UART_STOPBITS_2,
};
const uint16_t Start_Edge_Map[2] = {
    UART_RXDSTART_FALL,
    UART_RXDSTART_LOW,
};
const uint16_t First_Bit_Map[2] = {
    UART_FIRSTBIT_LSB,
    UART_FIRSTBIT_MSB,
};
const uint16_t Data_Width_Map[2] = {
    UART_DATAWIDTH_8BIT,
    UART_DATAWIDTH_9BIT,
};
const uint16_t CTSRTS_Mode_Map[4] = {
    UART_HWCONTROL_NONE,
    UART_HWCONTROL_CTS,
    UART_HWCONTROL_RTS,
    UART_HWCONTROL_CTS_RTS,
};

void UART1_Error_Callback(void)
{
    if(SYM_UART1->IER_f.FE == 1 && SYM_UART1->ISR_f.FE == 1)
    {
        SYM_UART1->ICR_f.FE = 0;
    }
    if(SYM_UART1->IER_f.ORE == 1 && SYM_UART1->ISR_f.ORE == 1)
    {
        SYM_UART1->ICR_f.ORE = 0;
    }
    if(SYM_UART1->IER_f.PE == 1 && SYM_UART1->ISR_f.PE == 1)
    {
        SYM_UART1->ICR_f.PE = 0;
    }
    if(SYM_UART1->IER_f.NE == 1 && SYM_UART1->ISR_f.NE == 1)
    {
        SYM_UART1->ICR_f.NE = 0;
    }
}
uint8_t Check_Uart1_Rx_empty(void)
{
    if(uart1_w_pos == uart1_r_pos)
    {
        return 1;//empty
    }
    return 0;//not empty
}
uint8_t Check_Uart1_Rx_full(void)
{
    if((uart1_w_pos + 1) % RX_LEN == uart1_r_pos)
    {
        return 1;//full
    }
    return 0;//not full
}
uint8_t Get_Uart1_Rx_data(void)
{
    uint8_t data = uart1_rxbuf[uart1_r_pos];
    uart1_r_pos += 1;
    if(uart1_r_pos >= RX_LEN)
    {
        uart1_r_pos = 0;
    }
    return data;
}
void UART1_RX_Callback(void)
{
    uart1_rxbuf[uart1_w_pos] = SYM_UART1->RDR_f.RDR;
    uart1_w_pos += 1;
    if(uart1_w_pos >= RX_LEN)
    {
        uart1_w_pos = 0;
    }
}
void UART1_TX_Callback(void)
{
    ;
}
void UART1_IDLE_Callback(void)
{
    ;
}
uint8_t Check_Uart2_Rx_empty(void)
{
    if(uart2_w_pos == uart2_r_pos)
    {
        return 1;//empty
    }
    return 0;//not empty
}
uint8_t Check_Uart2_Rx_full(void)
{
    if((uart2_w_pos + 1) % RX_LEN == uart2_r_pos)
    {
        return 1;//full
    }
    return 0;//not full
}
uint8_t Get_Uart2_Rx_data(void)
{
    uint8_t data = uart2_rxbuf[uart2_r_pos];
    uart2_r_pos += 1;
    if(uart2_r_pos >= RX_LEN)
    {
        uart2_r_pos = 0;
    }
    return data;   
}
void UART2_RX_Callback(void)
{
    uart2_rxbuf[uart2_w_pos] = SYM_UART2->RDR_f.RDR;
    uart2_w_pos += 1;
    if(uart2_w_pos >= RX_LEN)
    {
        uart2_w_pos = 0;
    }
}
void UART2_TX_Callback(void)
{
    ;
}
void UART2_IDLE_Callback(void)
{
    ;
}
void UART2_Error_Callback(void)
{
    if(SYM_UART2->IER_f.FE == 1 && SYM_UART2->ISR_f.FE == 1)
    {
        SYM_UART2->ICR_f.FE = 0;
    }
    if(SYM_UART2->IER_f.ORE == 1 && SYM_UART2->ISR_f.ORE == 1)
    {
        SYM_UART2->ICR_f.ORE = 0;
    }
    if(SYM_UART2->IER_f.PE == 1 && SYM_UART2->ISR_f.PE == 1)
    {
        SYM_UART2->ICR_f.PE = 0;
    }
    if(SYM_UART2->IER_f.NE == 1 && SYM_UART2->ISR_f.NE == 1)
    {
        SYM_UART2->ICR_f.NE = 0;
    }
}
void HAL_UART1_IRQHandler(void)
{
    if(SYM_UART1->IER_f.TXE == 1 && SYM_UART1->ISR_f.TXE == 1)
    {
        UART1_TX_Callback();
        SYM_UART1->ICR_f.TC = 0;
    }
    if(SYM_UART1->IER_f.RC == 1 && SYM_UART1->ISR_f.RC == 1)
    {
        UART1_RX_Callback();
        SYM_UART1->ICR_f.RC = 0;
    }
    if(SYM_UART1->IER_f.RXIDLE == 1 && SYM_UART1->ISR_f.RXIDLE == 1)
    {
        UART1_IDLE_Callback();
        SYM_UART1->ICR_f.RXIDLE = 0;
    }
    UART1_Error_Callback();
}
void HAL_UART2_IRQHandler(void)
{
    if(SYM_UART2->IER_f.TXE == 1 && SYM_UART2->ISR_f.TXE == 1)
    {
        UART2_TX_Callback();
        SYM_UART2->ICR_f.TC = 0;
    }
    if(SYM_UART2->IER_f.RC == 1 && SYM_UART2->ISR_f.RC == 1)
    {
        UART2_RX_Callback();
        SYM_UART2->ICR_f.RC = 0;
    }
    if(SYM_UART2->IER_f.RXIDLE == 1 && SYM_UART2->ISR_f.RXIDLE == 1)
    {
        UART2_IDLE_Callback();
        SYM_UART2->ICR_f.RXIDLE = 0;
    }
    UART2_Error_Callback();
}
const func_ptr_t SY_UART_RX_Callback_Map[2] = {
    UART1_RX_Callback,
    UART2_RX_Callback,
};
const func_ptr_t SY_UART_TX_Callback_Map[2] = {
    UART1_TX_Callback,
    UART2_TX_Callback,
};
const func_ptr_t SY_UART_IDLE_Callback_Map[2] = {
    UART1_IDLE_Callback,
    UART2_IDLE_Callback,
};
const func_ptr_t SY_UART_Error_Callback_Map[2] = {
    UART1_Error_Callback,
    UART2_Error_Callback,
};
int32_t bsp_uart_setbaud(uint8_t uart_num, uint32_t baudrate)
{
    uint32_t pclkfreq = HAL_SysCtrl_GetPclkFreq();
    uint32_t BRR = (pclkfreq + (baudrate>>1UL)) / baudrate;
    SY_UART_UNIT_Map[uart_num]->BRRI = BRR >> 4UL;
    SY_UART_UNIT_Map[uart_num]->BRRF = BRR;
    return BSP_OK;
}

int32_t bsp_uart_init(bsp_uart_init_t * uart_instance)
{
    /*check the parameters*/
    if(uart_instance == NULL){
        return BSP_BADPARA;
    }
    /*check Gpio parameters*/
    if(uart_instance->gpio_rx == NULL){
        return BSP_BADPARA;
    }
    if(uart_instance->gpio_tx == NULL){
        return BSP_BADPARA;
    }
    /*Enable the clock for the uart */
    if(uart_instance->uart_num == 0)
    {
        HAL_SYSCTRL_UART1_CLK_ENABLE();
    }
    else
    {
        HAL_SYSCTRL_UART2_CLK_ENABLE();
    }
    /*set the uart baudrate */
    bsp_uart_setbaud(uart_instance->uart_num,uart_instance->baudrate);
    /*init the gpio */
    bsp_gpio_init(uart_instance->gpio_rx);
    bsp_gpio_init(uart_instance->gpio_tx);
    SY_UART_UNIT_Map[uart_instance->uart_num]->CR1 = First_Bit_Map[uart_instance->firstbit] |\
            Parity_Mode_Map[uart_instance->parity] |\
            Stop_Bits_Map[uart_instance->stopbits] | 0x03;   
    SY_UART_UNIT_Map[uart_instance->uart_num]->CR2 = CTSRTS_Mode_Map[uart_instance->cts_rts];
//    SY_UART_UNIT_Map[uart_instance->uart_num]->CR1 |= 0x3;//enable TX,enable RX
    SY_UART_UNIT_Map[uart_instance->uart_num]->IER_f.RC = 1;//enable RX interrupt
    SY_UART_UNIT_Map[uart_instance->uart_num]->IER_f.RXIDLE = 1;//enable RX idle interrupt
    SY_UART_UNIT_Map[uart_instance->uart_num]->IER_f.ORE = 1;//enable overrun error interrupt
    SY_UART_UNIT_Map[uart_instance->uart_num]->IER_f.NE = 1;//enable noise error interrupt
    SY_UART_UNIT_Map[uart_instance->uart_num]->IER_f.FE = 1;//enable framing error interrupt
    SY_UART_UNIT_Map[uart_instance->uart_num]->IER_f.PE = 1;//enable parity error interrupt

    /*enable NVIC intterupt */
    switch(uart_instance->uart_num){
        case 0:
                NVIC_ClearPendingIRQ(UART1_IRQn);
                NVIC_EnableIRQ(UART1_IRQn);
                HAL_SYSCTRL_UART1_CLK_ENABLE();
            break;
        case 1:
                NVIC_ClearPendingIRQ(UART2_IRQn);
                NVIC_EnableIRQ(UART2_IRQn);
                HAL_SYSCTRL_UART2_CLK_ENABLE();
            break;
        default:
                return BSP_BADPARA;
    }
    return BSP_OK;
}

int32_t bsp_uart_deinit(bsp_uart_init_t * uart_instance)
{
    /*reset the uart */
    /*disable the clock for the uart */
    /*disable NVIC intterupt */
    switch(uart_instance->uart_num){
        case 0:
                SYM_SYSCTRL->APBRST1_f.UART1 = 0;
                SYM_SYSCTRL->APBRST1_f.UART1 = 1;
                HAL_SYSCTRL_UART1_CLK_DISABLE();
                NVIC_DisableIRQ(UART1_IRQn);
            break;
        case 1:
                SYM_SYSCTRL->APBRST1_f.UART2 = 0;
                SYM_SYSCTRL->APBRST1_f.UART2 = 1;
                HAL_SYSCTRL_UART2_CLK_DISABLE();
                NVIC_DisableIRQ(UART2_IRQn);
            break;
        default:
                return BSP_BADPARA;
    }
    return BSP_OK;
}

int32_t bsp_uart_send(bsp_uart_init_t * uart_instance, uint8_t * data, uint16_t len)
{
    UART_TypeDef*  pUARTx = SY_UART_UNIT_Map[uart_instance->uart_num];
    uint32_t i = 0;
    for(i = 0; i < len; i++)
    {
        while(pUARTx->ISR_f.TXE == 0);
        pUARTx->TDR = data[i];
    }
    return BSP_OK;
}
